TalentSync

AI resume builder and ATS optimizer for job seekers. Tailored resumes, outreach, and interview prep from one profile.

User management system

Google OAuth, FastAPI sessions, Prisma/SQLModel User rows, and role selection. NextAuth is gone.

This is the job-seeker TalentSync app. Recruiter as a UserRole value is leftover enum + /dashboard/recruiter chrome, not TalentSync-HR.

Repository layout#

  • frontend/app/auth/page.tsx
  • frontend/app/select-role/page.tsx
  • frontend/app/account/page.tsx
  • frontend/components/auth/role-selection-form.tsx
  • frontend/lib/session.ts
  • frontend/lib/user-roles.ts
  • backend/app/routes/auth.py
  • backend/app/routes/user.py
  • backend/app/models/tables/user.py
  • frontend/prisma/schema.prisma

Building blocks#

  • Google sign-in via /api/v1/auth/oauth/google
  • User.role enum default USER, roleSelectedAt for first-login pick
  • Session cookies owned by FastAPI
  • Account page: profile, avatar (POST /api/v1/user/update-avatar), delete account
  • Password and email-verify routes return 410 unless CREDENTIALS_AUTH_ENABLED

How it fits together#

Session#

Server: getSession() verifies the access JWT and hydrates Prisma User.

Client: useSession() from session-provider.tsx polls /me and refreshes the access cookie.

There is no NextAuth Prisma adapter. Account and Session tables still exist. Session is the hashed refresh store (familyId, previousToken). Prisma lists those models so the generated client matches the database. The comment on Session says do not write it from Next.js.

Registration and login#

Product login is Google. oauth_login creates or links the user, sets isVerified from Google’s assertion, and stores Account(provider=google).

Email/password register + verify is dead in production. Do not ship UI that POSTs /register expecting 201.

Roles#

USER_ROLE in frontend/lib/user-roles.ts: USER, RECRUITER, ADMIN. hasRecruitingAccess is true for recruiter and admin. That gates leftover candidate-DB UI in this repo, not the HR product.

Profile#

Account page shows name, email, image, role.

Avatar: AvatarUpload calls the user API then update() on the session provider so the navbar image refreshes.

Delete: DELETE /api/v1/auth/delete-account.

Schema (identity)#

Role is a column on User, not a separate Role table.

Dependencies#

Troubleshooting#

  • Google fails: redirect URI and client secrets. Not a NextAuth callback.
  • Role picker loops: roleSelectionRequired still true; confirm update-role wrote roleSelectedAt.
  • Avatar not showing: /user/update-avatar 401, or session not refreshed.
  • 410 on password routes: expected.